import numpy as np

class MetricsErrorChecker:

    @staticmethod
    def check_is_array(input_data):
        """
        检查输入数据是否为数组或列表。
        """
        if not isinstance(input_data, (np.ndarray, list)):
            raise ValueError(f"输入数据必须是列表或数组，类型为 {type(input_data)}，请检查。")

    @staticmethod
    def check_shapes_equal(y_true, y_pred):
        """
        检查 `y_true` 和 `y_pred` 的形状是否一致。
        """
        if y_true.shape != y_pred.shape:
            raise ValueError("`y_true` 和 `y_pred` 的形状不一致。")

    @staticmethod
    def check_valid_class_labels(y_true, y_pred, num_classes):
        """
        检查 `y_true` 和 `y_pred` 中的标签是否在有效的类别范围内 [0, num_classes-1]。
        """
        if np.any((y_true < 0) | (y_true >= num_classes)):
            raise ValueError(f"`y_true` 中的标签种类必须是{num_classes}个。")
        if np.any((y_pred < 0) | (y_pred >= num_classes)):
            raise ValueError(f"`y_pred` 中的标签种类必须是{num_classes}个。")

    @staticmethod
    def check_valid_numeric_data(y_true, y_pred):
        """
        检查 `y_true` 和 `y_pred` 是否为数值类型。
        """
        if not np.issubdtype(y_true.dtype, np.number) or not np.issubdtype(y_pred.dtype, np.number):
            raise ValueError("`y_true` 和 `y_pred` 必须是数值类型。")

    @staticmethod
    def check_valid_roc_scores(y_scores, num_classes):
        """
        检查 ROC 曲线的输入是否有效。
        - `y_scores` 中的每一列是否为概率值（即在 [0, 1] 范围内）。
        """
        if np.any((y_scores < 0) | (y_scores > 1)):
            raise ValueError("`y_scores` 中的值必须在 [0, 1] 范围内。")
        if y_scores.shape[1] != num_classes:
            raise ValueError(f"`y_scores` 的列数必须与 `num_classes` ({num_classes}) 一致。")

    @staticmethod
    def check_valid_classification_inputs(y_true, y_pred, num_classes):
        """
        检查分类任务的输入数据是否有效。
        调用前面定义的检查函数。
        """
        MetricsErrorChecker.check_is_array(y_true)
        MetricsErrorChecker.check_is_array(y_pred)
        y_true = np.array(y_true)
        y_pred = np.array(y_pred)
        MetricsErrorChecker.check_shapes_equal(y_true, y_pred)
        MetricsErrorChecker.check_valid_class_labels(y_true, y_pred, num_classes)

    @staticmethod
    def check_valid_regression_inputs(y_true, y_pred):
        """
        检查回归任务的输入数据是否有效。
        调用前面定义的检查函数。
        """
        MetricsErrorChecker.check_is_array(y_true)
        MetricsErrorChecker.check_is_array(y_pred)
        y_true = np.array(y_true)
        y_pred = np.array(y_pred)
        MetricsErrorChecker.check_shapes_equal(y_true, y_pred)
        MetricsErrorChecker.check_valid_numeric_data(y_true, y_pred)

    @staticmethod
    def check_valid_roc_inputs(y_true, y_scores, num_classes):
        """
        检查 ROC 曲线输入数据是否有效。
        调用前面定义的检查函数。
        """
        MetricsErrorChecker.check_is_array(y_true)
        y_true = np.array(y_true)
        MetricsErrorChecker.check_is_array(y_scores)
        y_scores = np.array(y_scores)
        MetricsErrorChecker.check_valid_roc_scores(y_scores, num_classes)

